package com.wj.config.security;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wj.config.security.component.*;
import com.wj.filter.LoginAfterFilter;
import com.wj.filter.LoginUsernamePasswordFilter;
import com.wj.pojo.Role;
import com.wj.pojo.User;
import com.wj.service.IUserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.List;

/**
 * Security配置类
 *
 * @author wj
 * @since 1.0.0
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
    @Resource
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
    @Resource
    private IUserService userService;
    @Resource
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Resource
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Resource
    private MyLogoutSuccessHandler logoutSuccessHandler;

    @Override
    @Bean
    protected UserDetailsService userDetailsService() {
        return username -> {
            User user = userService.getOne(new QueryWrapper<User>().eq("username", username));
            if (!ObjectUtils.isEmpty(user)) {
                List<Role> roles = userService.getUserWithRoleById(user.getId());
                user.setRoles(roles);
                return user;
            }
            throw new UsernameNotFoundException("用户没找到");
        };
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public LoginUsernamePasswordFilter loginUsernamePasswordFilter() throws Exception {
        LoginUsernamePasswordFilter login = new LoginUsernamePasswordFilter();
        login.setAuthenticationManager(authenticationManagerBean());//登录匹配认证处理器
        login.setFilterProcessesUrl("/login");//登录路径
        login.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);//登录成功处理
        login.setAuthenticationFailureHandler(myAuthenticationFailureHandler);//登录失败处理
        return login;
    }

    @Bean
    public LoginAfterFilter loginAfterFilter(){
        return new LoginAfterFilter();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //放行资源
        web.ignoring().antMatchers(
                "/test2",
                "/article/blog/**",
                "/captcha.png",
                "/user/register",
                "/css/**",
                "/js/**",
                "/index.html",
                "/favicon.ico"
        );

        web.ignoring().mvcMatchers(HttpMethod.GET,"/website-config");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.logout().logoutUrl("/logout").logoutRequestMatcher(new AntPathRequestMatcher("/logout","GET"))
                .logoutSuccessHandler(logoutSuccessHandler)
                .and().authorizeRequests().anyRequest().authenticated()//除了放行的全部要认证
                .and().csrf().disable();

        //自定义登录过滤器
        http.addFilterAt(loginUsernamePasswordFilter(), UsernamePasswordAuthenticationFilter.class);
        //自定义的未授权和未登录响应
        http.exceptionHandling().accessDeniedHandler(restfulAccessDeniedHandler).authenticationEntryPoint(restAuthenticationEntryPoint);
        //自定义登录之后过滤器
        http.addFilterAfter(loginAfterFilter(),UsernamePasswordAuthenticationFilter.class);
    }
}
